 /***************************************************************
文件名	: regmap_iic.c
版本   	: V1.0
描述   	:  IIO驱动程序
其他   	: 无
***************************************************************/
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/gpio.h>
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/of_gpio.h>
 #include <linux/semaphore.h>
 #include <linux/timer.h>
 #include <linux/i2c.h>
 #include <linux/miscdevice.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/regmap.h>
 #include "regmap_iic.h"

 #define BH1750_MINOR	255
 #define BH1750_NAME "light_drv"

 typedef struct {
	struct i2c_client *client;
	unsigned short value;
	struct regmap *regmap;
	struct regmap_config regmap_config;
 }bh1750_dev;

 bh1750_dev bh1750;

 /*
 * @description : 从 bh1750 读取多个寄存器数据
 * @param – dev : bh1750 设备
 * @param – reg : 要读取的寄存器首地址
 * @param – val : 读取到的数据
 * @param – len : 要读取的数据长度
 * @return : 操作结果
 */
static int bh1750_read_regs(bh1750_dev *dev, u8 reg,void *val )
 {
	int ret = 0;
	ret = regmap_read(dev->regmap,reg,(unsigned int*)val);
 	return ret;
 }

 /*
 * @description: 向 bh1750 多个寄存器写入数据
 * @param - dev: bh1750 设备
 * @param - reg: 要写入的寄存器首地址
 * @param - val: 要写入的数据缓冲区
 * @param - len: 要写入的数据长度
 * @return : 操作结果
 */
static s32 bh1750_write_regs(bh1750_dev *dev, u8 reg,unsigned int val)
{
	regmap_write(dev->regmap, reg, val);
	return 0;
 }

 /*
 * @description : 读取 bh1750 的数据，包括 ALS,PS 和 IR, 注意！如果同时
 * :打开 ALS,IR+PS 两次数据读取的时间间隔要大于 112.5ms
 * @param – ir : ir 数据
 * @param - ps : ps 数据
 * @param - ps : als 数据
 * @return : 无。
 */
 void bh1750_readdata(bh1750_dev *dev)
 {
 	char data_buf[2];

    memset(data_buf, 0, sizeof(data_buf));

	bh1750_write_regs(dev,RDADDR,PWON);
 	
	bh1750_write_regs(dev,RDADDR,CH_RM);

 	bh1750_read_regs(dev,RDADDR,data_buf);

	dev->value = (data_buf[0]<<8) | (data_buf[1]<<0);
 }


 /*
 * @description : 打开设备
 * @param – inode : 传递给驱动的 inode
 * @param - filp : 设备文件，file 结构体有个叫做 private_data 的成员变量
 * 一般在 open 的时候将 private_data 指向设备结构体。
 * @return : 0 成功;其他 失败
 */
static int bh1750_open(struct inode *inode, struct file *filp)
 {
	/* 设置私有数据 */
	filp->private_data = &bh1750;	
	return 0;
 }

 /*
 * @description : 从设备读取数据
 * @param - filp : 要打开的设备文件(文件描述符)
 * @param - buf : 返回给用户空间的数据缓冲区
 * @param - cnt : 要读取的数据长度
 * @param - offt : 相对于文件首地址的偏移
 * @return : 读取的字节数，如果为负值，表示读取失败
 */
static ssize_t bh1750_read(struct file *filp, char __user *buf,size_t cnt, loff_t *off)
 {
 	long err = 0;

	bh1750_dev *dev = (bh1750_dev*)filp->private_data;
	/* 读取bh1750数据*/
	bh1750_readdata(dev);

 	err = copy_to_user(buf, &dev->value, sizeof(dev->value));
 	return 0;
 }

 /*
 * @description : 关闭/释放设备
 * @param - filp : 要关闭的设备文件(文件描述符)
 * @return : 0 成功;其他 失败
 */
 static int bh1750_release(struct inode *inode, struct file *filp)
 {
 	return 0;
 }

 /* bh1750 操作函数 */
 static const struct file_operations bh1750_ops = {
 	.owner = THIS_MODULE,
 	.open = bh1750_open,
 	.read = bh1750_read,
 	.release = bh1750_release,
 };

 /* MISC设备结构体 */
 static struct miscdevice bh1750_miscdev = {
	.minor = BH1750_MINOR,
	.name = BH1750_NAME,
	.fops = &bh1750_ops,
 };

 /*
 * @description : i2c 驱动的 probe 函数，当驱动与
 * 设备匹配以后此函数就会执行
 * @param – client : i2c 设备
 * @param - id : i2c 设备 ID
 * @return : 0，成功;其他负值,失败
 */
static int bh1750_probe(struct i2c_client *client,const struct i2c_device_id *id)
 {
 	int ret = 0;
 	 
	/* 注册MISC子系统 */
	ret = misc_register(&bh1750_miscdev);
	if(ret < 0){
		printk("bh1750 misc device register failed!\r\n");
		ret = -EFAULT;
 	}

	/* 获取I2C设备 */
	bh1750.client = client;

	/* 初始化regmap_config设置 */
	bh1750.regmap_config.reg_bits = 8;		/* 寄存器长度8bit */
	bh1750.regmap_config.val_bits = 8;		/* 值长度8bit */

	/* 初始化I2C接口的regmap */
	bh1750.regmap = regmap_init_i2c(client, &bh1750.regmap_config);
	if(IS_ERR(bh1750.regmap)){
		return PTR_ERR(bh1750.regmap);
	}

	return 0;
 
 }

 /*
 * @description : i2c 驱动的 remove 函数，移除 i2c 驱动的时候此函数会执行
 * @param - client : i2c 设备
 * @return : 0，成功;其他负值,失败
 */
static int bh1750_remove(struct i2c_client *client)
 {
	int ret = 0;
	/*释放regmap*/
	regmap_exit(bh1750.regmap);
	/*MISC 驱动框架卸载*/
	misc_deregister(&bh1750_miscdev);
	return ret;
 }

 /* 传统匹配方式 ID 列表 */
 static const struct i2c_device_id bh1750_id[] = {
	{ "bh1750", 0 },
	{}
 };

 /* 设备树匹配列表 */
 static const struct of_device_id bh1750_of_match[] = {
	{ .compatible = "rohm,bh1750" },
	{ /* Sentinel */ }
 };

 /* i2c 驱动结构体 */ 
 static struct i2c_driver bh1750_driver = {
 	.probe = bh1750_probe,
 	.remove = bh1750_remove,
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "bh1750",
 		.of_match_table = bh1750_of_match,
    },
 	.id_table = bh1750_id,
 };
 
 /*
 * @description : 驱动入口函数
 * @param : 无
 * @return : 无
 */
 static int __init bh1750_init(void)
 {
 	int ret = 0;

 	ret = i2c_add_driver(&bh1750_driver);
 	return ret;
 }

 /*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
 static void __exit bh1750_exit(void)
 {
 	i2c_del_driver(&bh1750_driver);
 }

 /* module_i2c_driver(bh1750_driver) */

 module_init(bh1750_init);
 module_exit(bh1750_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("GEC");
 MODULE_INFO(intree, "Y");